package gu.sql2java.config;

import com.gitee.l0km.aocache.annotations.AoCacheable;
import com.gitee.l0km.common.spring.core.annotation.AnnotatedElementUtils;
import com.google.common.collect.FluentIterable;

import gu.sql2java.BaseBean;
import gu.sql2java.annotations.Sql2javaLocalConfig;

import static com.google.common.base.MoreObjects.firstNonNull;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Set;

/**
 * thread local manager for  {@link Sql2javaLocalConfig}
 * @author guyadong
 * @since 3.32.6
 */
public class RuntimeConfig {
	private static final ThreadLocal<RuntimeConfig> LOCAL_CONFIG = new ThreadLocal<>();

	private static final RuntimeConfig DEFAULT_CONFIG = new RuntimeConfig();
	private final Set<Class<? extends BaseBean>> resetModifiedIfEqual;
	
	private RuntimeConfig(Class<? extends BaseBean>[] resetModifiedIfEqual) {
		this.resetModifiedIfEqual = FluentIterable.from(resetModifiedIfEqual).toSet();
	}
	private RuntimeConfig(Sql2javaLocalConfig annot){
		this(annot.resetModifiedIfEqual());
	}

	@SuppressWarnings("unchecked")
	private RuntimeConfig() {
		this(new Class[] {});
	}
	public Set<Class<? extends BaseBean>> getResetModifiedIfEqual() {
		return resetModifiedIfEqual;
	}
	@Override
	public int hashCode() {
		return Objects.hash(resetModifiedIfEqual);
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		RuntimeConfig other = (RuntimeConfig) obj;
		return Objects.equals(resetModifiedIfEqual, other.resetModifiedIfEqual);
	}
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("RuntimeConfig [resetModifiedIfEqual=").append(resetModifiedIfEqual).append("]");
		return builder.toString();
	}
	public static void setLocalConfig(Sql2javaLocalConfig config) {
		if (null != config) {
			LOCAL_CONFIG.set(new RuntimeConfig(config));
		} else {
			LOCAL_CONFIG.remove();
		}
	}
	public static void removeLocalConfig() {
		LOCAL_CONFIG.remove();
	}

	public static RuntimeConfig getLocalConfig() {
		return firstNonNull(LOCAL_CONFIG.get(),DEFAULT_CONFIG);
	}
	@AoCacheable
	private static Sql2javaLocalConfig compile(Method method) {
		Sql2javaLocalConfig annot = AnnotatedElementUtils.getMergedAnnotation(method, Sql2javaLocalConfig.class);
		if(annot == null) {
			annot = AnnotatedElementUtils.getMergedAnnotation(method.getDeclaringClass(), Sql2javaLocalConfig.class);
		}
		return annot;
	}

	public static void installConfigOf(Method method) {
		RuntimeConfig.setLocalConfig(compile(method));		
	}
}
